/*
 * File:   ChessMove.cpp
 * Author: Michael Ziminsky
 *
 * Created on February 26, 2011, 10:26 PM
 */

#include "ChessMove.h"
#include <model/pieces/allpieces.h>
#include <iostream>

inline int ctoi(char c)
{
	return c - '0';
}

ChessMove::ChessMove(const std::string& str)
{
	boost::sregex_iterator s(str.begin(), str.end(), ChessMove::pattern);
	boost::sregex_iterator e;
	myTypes::movePtr tmp;
	for (; s != e; s++)
	{
		const boost::smatch& match = *s;
		using std::string;
		if (match.length(PLACEPATTERN))
		{
			char p = ((string)match[PIECETYPE])[0];
			bool l = tolower(((string)match[TEAM])[0]) == 'l';

			int r = ctoi(((string)match[PLACEROW])[0]);
			char c = ((string)match[PLACECOL])[0];

			tmp = myTypes::movePtr(new PlacePiece(ChessMove::charToPiece(p, l), model::Location(c, r)));
		}
		else if (match.length(MOVEPATTERN))
		{
			int fr = ctoi(((string)match[MOVEFROMROW])[0]);
			char fc = ((string)match[MOVEFROMCOL])[0];

			int tr = ctoi(((string)match[MOVETOROW])[0]);
			char tc = ((string)match[MOVETOCOL])[0];

			tmp = myTypes::movePtr(new MovePiece(model::Location(fc, fr), model::Location(tc, tr), match.length(MOVECAPTURE)));
		}
		else tmp = myTypes::movePtr(new InvalidMove(match[INVALID]));

		if (tmp)
		{
			moves.push_back(tmp);
			tmp.reset();
		}
	}
}

void ChessMove::execute(ChessGame& game) const
{
	for (std::list<myTypes::movePtr>::const_iterator i = moves.begin(); i != moves.end(); i++)
		(*i)->execute(game);
}

ChessMove::PlacePiece::PlacePiece(myTypes::cPiece p, const model::Location& loc) : loc(loc), piece(p) {}

void ChessMove::PlacePiece::execute(ChessGame& game) const
{
	game.addPiece(loc,piece);
//	std::cout << "Place a " << (piece->isLight ? "light " : "dark ") << *piece << " at " << loc << std::endl;
}

ChessMove::MovePiece::MovePiece(const model::Location& from, const model::Location& to, bool capture) :
	from(from), to(to), capt(capture)
{
}

void ChessMove::MovePiece::execute(ChessGame& game) const
{
	game.attemptMove(from, to);
	//std::cout << "From: " << from << " To: " << to << (capt ? " and capture piece" : "") << std::endl;
}

ChessMove::InvalidMove::InvalidMove(const std::string& move) : move(move) {}

void ChessMove::InvalidMove::execute(ChessGame& game) const
{
	std::cerr << "Invalid Move: " << move << std::endl;
}

myTypes::cPiece ChessMove::charToPiece(char c, bool light)
{
	myTypes::cPiece p;
	switch (toupper(c))
	{
		using namespace model::piece;
	case 'Q':
		p = myTypes::cPiece(new Queen(light));
		break;
	case 'K':
		p = myTypes::cPiece(new King(light));
		break;
	case 'R':
		p = myTypes::cPiece(new Rook(light));
		break;
	case 'N':
		p = myTypes::cPiece(new Knight(light));
		break;
	case 'B':
		p = myTypes::cPiece(new Bishop(light));
		break;
	case 'P':
		p = myTypes::cPiece(new Pawn(light));
		break;
	}
	return p;
}

const boost::regex ChessMove::pattern("\\b(([KQNRBP])([ld])([A-H])([1-8]))\\b|"
	"\\b(([A-H])([1-8])\\s([A-H])([1-8])([*])?(?!\\S))|"
	"(\\S+)", boost::regbase::icase);